#include <iostream>
#include "CWeapon.h"
#include "CGameApp.h"
using namespace std;

extern float VIEW_WIDTH;
extern float VIEW_HEIGHT;

CWeapon::CWeapon()
:CEntity(),
NumBullets(20),
Spread(3),
RateOfFire(2.3f),
FireTimer(0),
SpreadAngle(20.0f),
BulletLifeSpan(0.1f),
Ship(NULL)
{
	Bullets = new CEntity**[NumBullets];
	for( int x = 0; x < NumBullets; x++ )
	{
		Bullets[x] = new CEntity*[Spread];
		for( int y = 0; y < Spread; y++ )
		{
			Bullets[x][y] = new CEntity();
		} // next y
	} // next x
	SetType( "CWeapon" );
}

CWeapon::CWeapon( int numbullets, int spread )
:CEntity(),
NumBullets(numbullets),
Spread(spread),
RateOfFire(6.3f),
FireTimer(0),
SpreadAngle(10.0f),
BulletLifeSpan(0.3f),
Ship(NULL)
{
	//if i can make the inherited weapon class create the bullet array, this class won't have to thus making the child class
	//not have to destroy it and start over, or have it's own array of it's own bullets
	Bullets = new CEntity**[NumBullets];
	for( int x = 0; x < NumBullets; x++ )
	{
		Bullets[x] = new CEntity*[Spread];
		for( int y = 0; y < Spread; y++ )
		{
			Bullets[x][y] = new CEntity();
			//Bullets[x][y]->SetType( "WallBreaker" );
		} // next y
	} // next x
	SetType( "CWeapon" );
}

CWeapon::~CWeapon()
{
	if( Bullets )
	{
		for( int x = 0; x < NumBullets; x++ )
		{
			for( int y = 0; y < Spread; y++ )
			{
				delete Bullets[x][y];
			}
			delete[] Bullets[x];
			Bullets[x] = 0;
		}
		delete[] Bullets;
		Bullets = 0;
	} //endif 

	Ship = NULL; // the weapon shouldn't delete the pointer
}

void CWeapon::Render()
{
	//CEntity::Render();
	for( int x = 0; x < NumBullets; x++ )
	{
		for( int y = 0; y < Spread; y++ )
		{
			Bullets[x][y]->Render();
		}//next bullet in spread 
	}//next bullet
}

void CWeapon::Update()
{
	FireTimer += Ship->pParent->DeltaTime;
	for( int x = 0; x < NumBullets; x++ )
	{
		for( int y = 0; y < Spread; y++ )
		{
			//this should just call bullet->update()
			Bullets[x][y]->Update();

			//this bullet behavior is weapon dependant. put in weapon class
			if( Bullets[x][y]->GetAlive() )
			{
				//update bullet positions
				Bullets[x][y]->SetOldPos( Bullets[x][y]->GetPosX(), Bullets[x][y]->GetPosY() );

				Bullets[x][y]->MovePosY( Ship->pParent->DeltaTime * Bullets[x][y]->GetSpeed() * Bullets[x][y]->GetVelY() ); 
				Bullets[x][y]->MovePosX( Ship->pParent->DeltaTime * Bullets[x][y]->GetSpeed() * Bullets[x][y]->GetVelX() );

	for( int i=0; i < Ship->pParent->NumBlocks; i++ )
	{
		if( Ship->pParent->Block[i]->GetAlive() == false ) { continue; }
		float minx = Ship->pParent->Block[i]->GetPosX() - Ship->pParent->Block[i]->GetRadius();
		float maxx = Ship->pParent->Block[i]->GetPosX() + Ship->pParent->Block[i]->GetRadius();
		float miny = Ship->pParent->Block[i]->GetPosY() - Ship->pParent->Block[i]->GetRadius();
		float maxy = Ship->pParent->Block[i]->GetPosY() + Ship->pParent->Block[i]->GetRadius();

				CEntity* bullet = Bullets[x][y];
				if( bullet->GetAlive() == false ) { continue; }
				float cr    = bullet->GetCollisionRadius();
				float bminx = bullet->GetPosX() - cr;
				float bmaxx = bullet->GetPosX() + cr;
				float bminy = bullet->GetPosY() - cr;
				float bmaxy = bullet->GetPosY() + cr;
				if( bminx > maxx ) { continue; } //bullet to the right, no collision
				if( bmaxx < minx ) { continue; } //bullet to the left, no collision
				if( bminy > maxy ) { continue; } //bullet above, no collision
				if( bmaxy < miny ) { continue; } //bullet below, no collision
				//collision, do something
				if( Ship->pParent->Block[i]->Breakable == true )
				{
					Ship->pParent->Block[i]->TakeDamage( 1 );
					Ship->pParent->Block[i]->StartDamageAnimation();
				}
				bullet->Kill();//TakeDamage();
	}//next block

		#if 1
		//check for polygon collisions
	for( int j = 0; j < Ship->pParent->NumPolygons; j++ )
	{
		CPolygon* poly = &Ship->pParent->Polygons[j];//PolyBlock;
		CEntity* bullet = Bullets[x][y];

		if( poly->InBoundingBox( bullet ) == false ) { continue; }


		Vector2d prev,curr;
		//loop through each line of the polygon and check for collision with the bullet
		for( int i = 0; i < poly->NumVectors + 1; i++ )
		{
			//store the current vector
			curr = poly->Polygon[i% poly->NumVectors];
			if( i==0 ) { prev = curr; continue; }
			//got my line, time to test it against the bullet
			Vector2d vec = Vector2d( curr.x - prev.x , curr.y - prev.y );

			//vec is the vector of the line, norm is the normalized normal of vec
			//need to test line collision between vec and the bullet
			Vector2d bvec = Vector2d( bullet->GetPosX() - bullet->GetOldPosX() , bullet->GetPosY() - bullet->GetOldPosY() );
			Vector2d bstart = bullet->OldPos;
			Vector2d bend	= bullet->Pos;
			//bstart bend is the bullet start and end point, bvec is the line from the old bullet pos to the current pos
			//prev and curr is the line start and end point, vec is the line from one point on the polygon to another, clockwise
			//norm is the normal of vec, facing away from the polygon

			float f = ( vec.y * bvec.x ) - ( vec.x * bvec.y );
			Vector2d c = Vector2d( bend.x - curr.x , bend.y - curr.y ); // end points of the bullet and line
			float aa = ( vec.y * c.x ) - ( vec.x * c.y );
			float bb = ( bvec.y * c.x ) - ( bvec.x * c.y );

			bool s = true;
			if(f <= 0)
			{
				if(aa > 0 || bb > 0 || aa < f || bb < f )   { s = false; }
				//if(bb > 0)    { s = false; }
				//if(aa < f)    { s = false; }
				//if(bb < f)    { s = false; }
			}
			if( f > 0 )
			{
				if(aa < 0 || bb < 0 || aa > f || bb > f )   { s = false; }
				//if(aa < 0 )   { s = false; }
				//if(bb < 0)    { s = false; }
				//if(aa > f)    { s = false; }
				//if(bb > f)     { s = false; }
			}
			
			if( s == true )
			{
				float contact = 1.0f - (aa/f);
				bullet->Pos.x = ((bvec.x) * contact) + bstart.x;
				bullet->Pos.y = ((bvec.y) * contact) + bstart.y;
				Vector2d norm = Vector2d( vec.y*-1, vec.x );
				//normalize it
				float length = sqrtf( norm.x * norm.x + norm.y * norm.y );
				norm.x /= length;
				norm.y /= length;
				//cout << vec.x << " " << vec.y << " " << i << norm.x << " " << norm.y << endl;

				//cout << norm.x << " " << norm.y << " " << bvec.x << " " << bvec.y << endl;
				Vector2d u = Vector2d( 1*norm.x * (bvec.x * norm.x + bvec.y * norm.y) , 1*norm.y * (bvec.x * norm.x + bvec.y * norm.y) );
				Vector2d w = Vector2d( bvec.x - u.x, bvec.y - u.y );
				Vector2d newvec = Vector2d( w.x - u.x , w.y - u.y );
				//newvec.x *= 100;
				//newvec.y *= 100;
				length = sqrtf( newvec.x * newvec.x + newvec.y * newvec.y );
				newvec.x /= length;
				newvec.y /= length;
			// bool only = true;
			//if( only == true )
			//{
			//	cout << "bullet direction     " << bvec.x << " " << bvec.y << endl;
			//	cout << "line normal          " << norm.x << " " << norm.y << endl;
			//	cout << "new bullet direction " << newvec.x << " " << newvec.y << endl;
			//	only = false;
			//}
				//cout << newvec.x << " " << newvec.y << endl;
				//bullet->SetFaceAngle( newvec.x, newvec.y );
				if( newvec.x < 0 )		{ bullet->m_fFaceAngle = ( (atan( newvec.y/newvec.x )*57.2958f)+180 ); }
				if( newvec.x >= 0 )		{ bullet->m_fFaceAngle = ( atan( newvec.y/newvec.x )*57.2958f ); }
				//bullet->SetVel( newvec.x, newvec.y ); //norm.x, norm.y );
				//bullet->MovePosX( norm.x * 0.01f );
				//bullet->MovePosY( norm.y * 0.01f );
				//v is the bullet velocity vector
				//w is parallel to the wall
				//u is perpindicular to it
				//n is the normal
				//v2 is the new velocity vector for the bullet


				bullet->Kill();
			}
			//bullet->GetPos = bullet->G->Get*out = 1.0 - (aa / f);
			//Point intersection = ((B2 - B1) * out) + B1;

			//bstart + bvec*t

			prev = curr;
		}
	}//next polygon
	#endif




				//check out of bounds
				float edge = pParent->WorldEdge;
				if( Bullets[x][y]->GetPosY() > edge ) { Bullets[x][y]->Kill(); continue; }//VIEW_HEIGHT * 0.5f )	{ Bullets[x][y]->Kill(); continue;}
				if( Bullets[x][y]->GetPosY() < -edge ) { Bullets[x][y]->Kill(); continue; }//VIEW_HEIGHT *-0.5f )	{ Bullets[x][y]->Kill(); continue;}
				if( Bullets[x][y]->GetPosX() > edge ) { Bullets[x][y]->Kill(); continue; }//VIEW_WIDTH  * 0.5f )	{ Bullets[x][y]->Kill(); continue;}
				if( Bullets[x][y]->GetPosX() < -edge ) { Bullets[x][y]->Kill(); continue; }//VIEW_WIDTH  *-0.5f )	{ Bullets[x][y]->Kill(); }
			}
		}//next spread
	}//next bullet
}

//bool CWeapon::Collision( CEntity* test )
//{
/*
cgameapp::checkcollision()
	player->collision( enemywave )
	//player collision with level blocks happens in update but the level blocks probably should have their own collision event
	//it would be something like player->collision( levelblocks ) or player->levelcollision
	//the level blocks should have some kind of function that takes a ships position and updates it to not be colliding with it
	enemywave isn't a CEntity so maybe enemywave could handle the collision
	enemywave->Collision( player )
	//anyway
	for each enemy
		Player->Collision( enemy[i] )

		//inside player collision
		CEntity::collision( enemy )		//to use the base class collision to avoid infinite recursion
		if enemy and player are still alive
			primaryweapon->collision( enemy->primaryweapon )
			//weapon collision is dependent on the weapon
			//normally
			for each bullet in the array
				for each spread in the bullet
					CEntity::collision


*/
//}


void CWeapon::Load()
{
	if( Ship == NULL )	{ cout << "weapon load failed, no player attached" << endl; return; }
	SetGame(Ship->pParent);
	for( int x = 0; x < NumBullets; x++ )
	{
		for( int y = 0; y < Spread; y++ )
		{
			Bullets[x][y]->SetAlive( false );
			Bullets[x][y]->SetGame( Ship->pParent );
			Bullets[x][y]->SetHealth( 1 );
			Bullets[x][y]->SetDamage( 1 );
			Bullets[x][y]->SetFaceAngle( 90.0f );
			Bullets[x][y]->SetPos( -9.0f + x*2, Ship->GetPosY() );
			Bullets[x][y]->SetVel( Ship->GetVelX(), Ship->GetVelY() );
			Bullets[x][y]->SetSpeed( 15.4f );
			Bullets[x][y]->SetRotateSpeed( 0.0f );
			Bullets[x][y]->SetSize( 0.8f );
			Bullets[x][y]->SetCollisionSize( 0.25f );
			Bullets[x][y]->SetTexture( Ship->pParent->BulletBreakTexture.texID );
			Bullets[x][y]->SetFireAnimationTexture( Ship->pParent->FireAnimationTexture );
			Bullets[x][y]->SetExplosionTexture( Ship->pParent->ExplosionTexture );
			Bullets[x][y]->SetType( "WallBreaker" );
			//Bullets[x][y]->SetLifeSpan( 1.0f );
		}//next bullet in the spread
	}//next bullet
}

void CWeapon::TakeDamage(float damage)
{
	for( int x = 0; x < NumBullets; x++ )
	{
		for( int y = 0; y < Spread; y++ )
		{
			Bullets[x][y]->SetHealth( Bullets[x][y]->GetHealth() - damage );
			if( Bullets[x][y]->GetHealth() <= 0 ) { Bullets[x][y]->Kill(); } 
		}
	}

}

void CWeapon::Kill()
{
	for( int x = 0; x < NumBullets; x++ )
	{
		for( int y = 0; y < Spread; y++ )
		{
			if( Bullets[x][y]->GetAlive() )
			{
				Bullets[x][y]->Kill();
			}
		}
	}
}

void CWeapon::FireBullet()
{
	//if the ship is dead, the ship can't fire
	if( Ship->GetAlive() == false ) { return; }

	//if not enough time has passed, the ship can't fire
	if( FireTimer <= 1/RateOfFire ) { return; }

	bool done = false;//when done is true, a bullet is fired and no more needs to be
	bool rowcanshoot = true; //will remain true as long as every bullet in the spread can fire
	//loop through the bullets
	for( int x = 0; x < NumBullets; x++ )
	{
		if( done == true ) { break; }//bullet fired, no need to add more
		rowcanshoot = true;
		for( int y = 0; y < Spread; y++ )
		{
			if( Bullets[x][y]->GetAlive() || Bullets[x][y]->GetEAlive() )
			{
				rowcanshoot = false;
				break;
			}
		}
		if( rowcanshoot == false ) { continue; }
		for( int y = 0; y < Spread; y++ )
		{
			//if( done == true ) { continue; }//bullet fired, no need to add more
			//if( Bullets[x][y]->GetAlive() ) { continue; }//bullet active, don't reset it yet
			pParent->audio->Play("fire");
			Bullets[x][y]->SetAlive( true );
			Bullets[x][y]->SetLifeSpan( BulletLifeSpan );
			//Bullets[x][y]->SetFaceAngle( Bullets[x][y]->GetFaceAngle() -90 );
			float tempx = cos((Ship->GetFaceAngle()-90)*0.0174533f);
			float tempy = sin((Ship->GetFaceAngle()-90)*0.0174533f);
			SetVel( cos(GetFaceAngle()*0.0174533f), sin(GetFaceAngle()*0.0174533f) );
			//set the position to the point of the gun, position plus vel scaled by radius
			Bullets[x][y]->SetPos( Ship->GetPosX() + tempx*Ship->GetCollisionRadius()*0.9f,Ship->GetPosY() + tempy*Ship->GetCollisionRadius()*0.9f );
			//setfaceangle to adjust to spread angle
			Bullets[x][y]->SetFaceAngle( Ship->GetFaceAngle() - (((Spread - 1)*SpreadAngle)/2 ) + y * SpreadAngle-90 );
			//bullets(n,p).faceangle   = GetFaceAngle() - (((Spread - 1)*SpreadAngle)/2 ) + y * SpreadAngle
			//bullets(n,p).velx        = sin(bullets(n,p).faceangle)
			//bullets(n,p).vely        = -cos(bullets(n,p).faceangle)
			//have to rotate the face angle, switch later to other setfaceangle
			//only this setfaceangle sets it based on direction, not a point in space
			//need to reemplement pointto
			//Bullets[x][y]->RotateFaceAngleBy( 90.0f );
			Bullets[x][y]->StartFireAnimation();
			//Bullets[x][y]->SetFirePos( Ship->GetPosX() + Ship->GetVelX()*Ship->GetCollisionRadius()*0.9f,Ship->GetPosY() + Ship->GetVelY()*Ship->GetCollisionRadius()*0.9f );
			//cout << Bullets[x][y]->GetPosX() << " " << Bullets[x][y]->GetPosY() << endl;

			done = true;
		}//next spread
	}//next bullet
	FireTimer = 0;
//}//endif bullet can be fired

}

void CWeapon::SetBulletSpeed( float bulletspeed )
{
	for( int x = 0; x < NumBullets; x++ )
	{
		for( int y = 0; y < Spread; y++ )
		{
			Bullets[x][y]->SetSpeed( bulletspeed );
		}
	}
}

void CWeapon::SetBulletDamage( float damage )
{
	for( int x = 0; x < NumBullets; x++ )
	{
		for( int y = 0; y < Spread; y++ )
		{
			Bullets[x][y]->SetDamage( damage );
		}
	}
}


